#include "Utils.h"
#include "Worker.h"
#include "NetWork.h"
//客户端线程池定义
int thread_num = 0;
long thread_tid[1024]={0};
int signup_flag = 0;
int login_flag = 0;

typedef struct ClientQueueNode_s
{
    pthread_t tid;
    struct ClientQueueNode_s* next;
    int net_fd;
    int id;
    char p[1024];
}ClientQueueNode;
typedef struct ClientQueue_s
{
    ClientQueueNode* front;
    ClientQueueNode* rear;
    int queue_size;
}ClientQueue;
typedef struct ClientPool_s{
    ClientQueue queue;
    pthread_mutex_t mutex;
    pthread_cond_t cond;
}ClientPool;
int ClientQueueInit(ClientQueue * queue){
    bzero(queue, sizeof(ClientQueue));
    return 0;
}
int Client_EnQueue(ClientQueue *queue, int net_fd, int id,char* p){
    ClientQueueNode*new_node = (ClientQueueNode *)calloc(1, sizeof(ClientQueueNode));
    new_node->net_fd = net_fd;
    new_node->id = id;
    memcpy(new_node->p,p,strlen(p));
    if(queue->queue_size == 0){
        queue->front = new_node;
    }else{
        queue->rear->next = new_node;
    }
    queue->rear = new_node;
    ++queue->queue_size;
    return 0;
}
int Clietn_DeQueue(ClientQueue *queue){
    ClientQueueNode *temp = queue->front;
    queue->front = queue->front->next;
    if(queue->queue_size == 1){
        queue->rear = NULL;
    }
    free(temp);
    --queue->queue_size;
    return 0;
}
int ClientPoolInit(ClientPool *thread_pool){
    ClientQueueInit(&thread_pool->queue);
    pthread_mutex_init(&thread_pool->mutex,NULL);
    pthread_cond_init(&thread_pool->cond,NULL);
    return 0;
}

//常量定义
typedef struct Train_s
{
    int length;
    char data[1000];
}Train;
const char* command_name[]={"cd","pwd","ls","puts","gets","rm","mkdir","rmdir","login","logout","signup"};
//根据截取的命令，判断flag
int selectFlag(int len,char* p){
    if(len == 0){
        return -1;
    }
    for(int i =0;i<10;i++){
        //if(memcmp(command_name[i],p,len) == 0)
        if((strcmp(command_name[i],p))==0)
        {
            return i;
        }
    }
    return -1;
}
//检测输出区，输出ctrl+d关闭客户端
int sendId(int id,int net_fd){
    char buf[100]={0};
    sprintf(buf, "%d", id);
    SendTrain(net_fd,buf);
    return 0;
}
int exitClient(int ret,int sockfd){
    if(ret == 0)
    {
        printf("close client\n");
        close(sockfd);
        printf("thread_num = %d\n",thread_num);
        for (int i = 0; i < thread_num; i++) {
            pthread_join(thread_tid[i], NULL);
        }
        exit(0);
    }
    return 0;
}
void *ClientFunc(void *arg)
{
    ClientPool* pool=(ClientPool*)arg;
    pthread_mutex_lock(&pool->mutex);
    int net_fd = pool->queue.front->net_fd;
    int id = pool->queue.front->id;
    char p[1024] = {0};
    memcpy(p,pool->queue.front->p,strlen(pool->queue.front->p));
    Clietn_DeQueue(&pool->queue);
    pthread_mutex_unlock(&pool->mutex);
    if(id == GETS)
    {
        printf("开始下载\n");
        ClientGetsHandler(net_fd,p);
        printf("下载完毕\n");
    }
    else if(id == PUTS)
    {
        printf("开始上传\n");
        ClientPutsHandler(net_fd,p);
        printf("上传完毕\n");
    }
    close(net_fd);
    pthread_exit(NULL);
}
int LongLink(int net_fd,int id,char* token,char* p,ClientPool* pool,struct sockaddr_in* addr)
{
    //新建链接
    char begin[4]={0};
    RecvTrain(net_fd,begin);
    int sockfd =socket(AF_INET,SOCK_STREAM,0);
    ERROR_CHECK(sockfd,-1,"socket");
    int ret = connect(sockfd,(struct sockaddr*)addr,sizeof(*addr));
    ERROR_CHECK(ret,-1,"connect");
    //验证
    SendTrain(net_fd,token);
    char flag[4]="0";
    RecvTrain(net_fd,flag);
    if(memcmp(flag,"1",1)==0)
    {
    printf("sockfd =%d\n",sockfd);
        printf("Token 验证成功!\n");
        pthread_mutex_lock(&pool->mutex);
        Client_EnQueue(&pool->queue,sockfd,id,p);
        pthread_create(&(pool->queue.front->tid),NULL,ClientFunc,pool);
        thread_tid[thread_num] = pool->queue.front->tid;
        thread_num += 1;
        pthread_mutex_unlock(&pool->mutex);
    }
    else
    {
        printf("Token 验证失败!\n");
        close(sockfd);
        return 1;
    }
    return 0;
}
//退出登陆,重新连接等待登陆
int Logout(int* sockfd,int* link,struct sockaddr_in* addr,int epfd){
    sendId(LOGOUT,*sockfd);
    *link = -1;
    printf("已经退出登陆\n");
    //关闭套接字监听，关闭套接字
    int ret = epoll_ctl(epfd,EPOLL_CTL_DEL,*sockfd,NULL);
    ERROR_CHECK(ret,-1,"epoll_ctl del");
    close(*sockfd);
    //重新建立套接字，并连接
    *sockfd =socket(AF_INET,SOCK_STREAM,0);
    ERROR_CHECK(*sockfd,-1,"sockfd");
    ret = connect(*sockfd,(struct sockaddr*)addr,sizeof(*addr));
    ERROR_CHECK(ret,-1,"connect");
    //监听新的套接字
    EpollAdd(epfd,*sockfd,EPOLLIN);
    return 0;
}
int SignUp_before(char* user,int net_fd)
{
    sendId(SIGNUP,net_fd);
    Train train;
    bzero(&train,sizeof(train));
    train.length = strlen(user);
    memcpy(train.data,user,train.length);
    send(net_fd,&train,sizeof(int)+train.length,MSG_NOSIGNAL);

    printf("请输入密码：\n");
    return 0;
}
int SignUp(char* pd,int net_fd)
{
    sendId(SIGNUP,net_fd);
    Train train;
    bzero(&train,sizeof(train));
    train.length = strlen(pd);
    memcpy(train.data,pd,train.length);
    send(net_fd,&train,sizeof(int)+train.length,MSG_NOSIGNAL);

    char user[1024]={0};
    bzero(user,sizeof(user));
    RecvTrain(net_fd,user);
    if(memcmp(user,"1",1) == 0){
        printf("注册成功\n");
        return 0;
    }
    printf("注册失败\n");
    return 0;
}
//根据flag，调用工作函数
int handle(int* sockfd,int flag,char* p,int len,int* link,struct sockaddr_in* addr,int epfd,ClientPool* pool,char* token){
    switch(flag)
    {
    case CD:
        if(len == 0)
        {
            printf("Args is error!\n");
            break;
        }
        sendId(flag,*sockfd);
        ClientCdHandler(*sockfd,p);
        break;
    case PWD:
        if(len != 0)
        {
            printf("Args is error!\n");
            break;
        }
        sendId(flag,*sockfd);
        ClientPwdHandler(*sockfd,p);
        break;
    case LS:
        sendId(flag,*sockfd);
        ClientLsHandler(*sockfd,p);
        break;
    case PUTS:
        if(len == 0)
        {
            printf("Args is error!\n");
            break;
        }
        sendId(flag,*sockfd);
        LongLink(*sockfd,flag,token,p,pool,addr);
        break;
    case GETS:
        if(len == 0)
        {
            printf("Args is error!\n");
            break;
        }
        sendId(flag,*sockfd);
        LongLink(*sockfd,flag,token,p,pool,addr);
        break;
    case RM:
        if(len == 0)
        {
            printf("Args is error!\n");
            break;
        }
        sendId(flag,*sockfd);
        ClientRmHandler(*sockfd,p);
        break;
    case MKDIR:
        if(len == 0)
        {
            printf("Args is error!\n");
            break;
        }
        sendId(flag,*sockfd);
        ClientMkdirHandler(*sockfd,p);
        break;
    case RMDIR:
        if(len == 0)
        {
            printf("Args is error!\n");
            break;
        }
        sendId(flag,*sockfd);
        ClientRmdirHandler(*sockfd,p);
        break;
    case LOGOUT:
        Logout(sockfd,link,addr,epfd);
        break;
    default:
        printf("Args is error!\n");
        break;
    }
    return 0;
}

int Login_before(char* user,int net_fd)
{
    sendId(LOGIN,net_fd);
    Train train;
    bzero(&train,sizeof(train));
    train.length = strlen(user);
    memcpy(train.data,user,train.length);
    send(net_fd,&train,sizeof(int)+train.length,MSG_NOSIGNAL);
    printf("请输入密码：\n");
    return 0;
}
int Login(char* pd,int net_fd,int* link,char* token){
    
    sendId(LOGIN,net_fd);
    //接收salt
    char salt[1024]={0};
    bzero(salt,sizeof(salt));
    RecvTrain(net_fd,salt);
    //接收密码，生成密文
    char md5[33]={0};
    Md5(pd,salt,md5);
    SendTrain(net_fd,md5);
   
    char user[1024]={0};
    bzero(user,sizeof(user));
    RecvTrain(net_fd,user);
    if(memcmp(user,"1",1) == 0){
        *link = 1;
        printf("登录成功\n");
        bzero(token,strlen(token));
        RecvTrain(net_fd,token);
        return 0;
    }
    printf("登陆失败\n");
    return 0;
}

int main(int argc,char*argv[]){
    ARGC_CHECK(argc,3);
    //建立socket连接
    int sockfd  = -1;
    sockfd =socket(AF_INET,SOCK_STREAM,0);
    ERROR_CHECK(sockfd,-1,"sockfd");
    struct sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = inet_addr(argv[1]);
    addr.sin_port = htons(atoi(argv[2]));
    int ret = connect(sockfd,(struct sockaddr*)&addr,sizeof(addr));
    ERROR_CHECK(ret,-1,"connect");
    //建立epoll，监听输入缓冲区和套接字
    int epfd = epoll_create(1);
    ERROR_CHECK(epfd,-1,"epoll_create");
    EpollAdd(epfd,STDIN_FILENO,EPOLLIN);
    EpollAdd(epfd,sockfd,EPOLLIN);
    //创建动态线程
    ClientPool client_pool;
    ClientPoolInit(&client_pool);

    int readyNum = 0;
    char buf[4096]={0};
    struct epoll_event evs[1024];
    int flag = -1;
    int link = -1;
    char token[209]={0};
    while(1){
        if(link == -1 && login_flag == 0 && signup_flag == 0)
        {
            printf("未登录\n");
            printf("输入login登陆，输入signup注册：\n");
        }
        else if (link == 1){
            printf("请输入参数\n");
        }
        readyNum = epoll_wait(epfd,evs,1024,-1);
        for(int i =0;i<readyNum;i++){
            if(evs[i].data.fd == STDIN_FILENO){
                if(link == -1)
                {
                    bzero(buf,sizeof(buf));
                    int ret = read(STDIN_FILENO,&buf,sizeof(buf));
                    ERROR_CHECK(ret,-1,"read sdtin");
                    exitClient(ret,sockfd);
                    char command[1024]={0};
                    bzero(command,sizeof(command));
                    memcpy(command,buf,strlen(buf)-1);
                    if(signup_flag == 1)
                    {
                        SignUp(command,sockfd);
                        signup_flag = 0;
                    }
                    else if(login_flag == 1)
                    {
                        Login(command,sockfd,&link,token);
                        login_flag = 0;
                    }
                    else if(login_flag == 2)
                    {
                        Login_before(command,sockfd);
                        login_flag = 1;
                    }
                    else if(memcmp(command,"login",5)==0)
                    {
                        sendId(LOGIN,sockfd);
                        printf("开始登陆，请输入用户名：\n");
                        login_flag = 2;
                    }
                    else if(signup_flag == 2)
                    {
                        SignUp_before(command,sockfd);
                        signup_flag = 1;
                    }
                    else if(memcmp(command,"signup",6)==0)
                    {
                        sendId(SIGNUP,sockfd);
                        printf("开始注册，请输入用户名：\n");
                        signup_flag = 2;
                    }
                    else
                    {
                        printf("Args is error!\n");
                    }
                }
                else
                {
                    bzero(buf,sizeof(buf));
                    int ret = read(STDIN_FILENO,&buf,sizeof(buf));
                    ERROR_CHECK(ret,-1,"read stdin");
                    //输入crtl+d，关闭客户端
                    exitClient(ret,sockfd);
                    //截取命令，判断flag
                    char command[1024]={0};
                    bzero(command,sizeof(command));
                    int i =0;
                    while(buf[i]){
                        if(buf[i] == ' ')
                        {
                            break;
                        }
                        else if(buf[i] == '\n')
                        {
                            break;
                        }
                        *(command+i) =*(buf+i);
                        i++;
                    }
                    //char* p = strtok(buf," ");
                    printf("command = %s\n",command);
                    int len = strlen(command);
                    flag = selectFlag(len,command);
                    //获取剩余参数
                    char* p = strtok(buf," ");
                    p = strtok(NULL,"\n");
                    if(p != NULL)
                    {
                        len = strlen(p);
                    }
                    else
                    {
                        len = 0;
                    }//调用工作函数
                    printf("begin handle\n");
                    ret = handle(&sockfd,flag,p,len,&link,&addr,epfd,&client_pool,token);
                    printf("end handle\n");
                }
            }
            else if(evs[i].data.fd == sockfd){
                bzero(buf,sizeof(buf));
                int ret = recv(sockfd,&buf,sizeof(buf),0);
                if(ret == 0)
                {
                    exitClient(ret,sockfd);
                }
            }
        }
    }
    return 0;
}

